<!-- Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->

<link rel="import" href="../common/cr-keyboard.html">

<polymer-element name="cr-user-autocomplete" attributes="value">
    <template>
        <style>
            :host {
                -webkit-user-select: none;
            }

            #completions {
                position: absolute;
                border: 1px solid #dcdcdc;
                border-top: none;
                background-color: white;
                left: 0;
                right: 0;
                margin: 0 16px;
                font-family: Menlo, Monaco, monospace;
                font-size: 0.9em;
                z-index: 1;
                cursor: default;
            }

            .completion {
                padding: 0.5em 16px;
            }

            .selected {
                background-color: #eee;
            }

            .completion:focus {
                outline: none;
            }
        </style>

        <content on-focusout="{{ dismiss }}"></content>

        <template if="{{ completions.length }}">
            <div id="completions" on-tap="{{ commit }}" on-focusin="{{ preventDismiss }}" on-focusout="{{ allowDismiss }}" on-mouseover="{{ selectOption }}">
                <template repeat="{{ user, i in completions }}">
                    <div data-index="{{ i }}" class="completion {{ {selected:i == selectedIndex} | tokenList }}" tabindex="0">
                        {{ user.email }}
                        ({{ user.name }})
                    </div>
                </template>
            </div>
            <cr-keyboard
                on-key-down="{{ nextOption }}"
                on-key-up="{{ previousOption }}"
                on-key-enter="{{ commit }}"></cr-keyboard>
        </template>
    </template>
    <script>
        Polymer({
            created: function() {
                this.value = "";
                this.termRange = {};
                this.completions = [];
                this.didComplete = false;
                this.shouldDismiss = true;
                this.active = false;
                this.selectedIndex = 0;
            },
            dismiss: function() {
                if (!this.shouldDismiss)
                    return;
                this.async(function() {
                    if (this.shouldDismiss)
                        this.resetAutocomplete();
                });
            },
            preventDismiss: function() {
                this.shouldDismiss = false;
            },
            allowDismiss: function() {
                this.shouldDismiss = true;
            },
            completionsChanged: function(oldValue, newValue) {
                this.active = newValue.length;
                this.selectedIndex = 0;
            },
            nextOption: function(event) {
                event.preventDefault();
                this.selectedIndex = Math.min(this.completions.length - 1, this.selectedIndex + 1);
            },
            previousOption: function(event) {
                event.preventDefault();
                this.selectedIndex = Math.max(0, this.selectedIndex - 1);
            },
            selectOption: function(event) {
                if (!event.target.classList.contains("completion"))
                    return;
                this.selectedIndex = event.target.dataset.index;
            },
            valueChanged: function(oldValue, newValue) {
                var NAME_PATTERN = /[a-z0-9.\-_]+/;
                var WHITESPACE = /\s/;
                var self = this;
                if (this.didComplete) {
                    this.didComplete = false;
                    return;
                }
                this.resetAutocomplete();
                var input = this.querySelector("input");
                if (!input.matches(":focus"))
                    return;
                var selectionStart = input.selectionStart;
                var end = this.value.indexOf(",", selectionStart);
                if (end == -1)
                    end = this.value.length;
                var start = this.value.lastIndexOf(",", end - 1) + 1;
                while (WHITESPACE.test(this.value[start]))
                    start++;
                var name = this.value.substring(start, end);
                if (!NAME_PATTERN.test(name))
                    return;
                this.termRange = {
                    start: start,
                    end: end,
                    text: name,
                };
                Search.findUsers(name).then(function(users) {
                    // Don't overwrite completions if a new search has been made.
                    if (self.termRange.text == name)
                        self.completions = users;
                });
            },
            commit: function(event) {
                event.preventDefault();

                var user = this.completions[this.selectedIndex];
                if (!user)
                    return;

                this.didComplete = true;

                var input = this.querySelector("input");
                var range = this.termRange;
                var value = user.email.substring(range.text.length) + ", ";

                // Restore selection to where the autocomplete expects it. This prevents the user from
                // selecting some random text and then clicking a suggestion which might destroy their
                // input. We might also dismiss the suggestions if the selection moves but there's no
                // obvious way to detect that.
                input.selectionStart = range.end;
                input.selectionEnd = input.selectionStart;

                // For Safari/Chrome:
                // Simulate the user entering the text. This makes undo work properly instead of using
                // data binding which is like a big "replace" action.
                var inputEvent = document.createEvent("TextEvent");
                if (inputEvent.initTextEvent) {
                    inputEvent.initTextEvent("textInput", true, true, window, value, 0, "en-US");
                    input.dispatchEvent(inputEvent);
                } else if (window.InputEvent) {
                    // For Firefox we can just update the value and undo will work.
                    input.value = input.value.to(input.selectionEnd) + value + input.value.from(input.selectionEnd);
                    input.dispatchEvent(wrap(new InputEvent("input", {
                        data: value,
                        bubbles: true,
                        cancelable:false
                    })));
                }

                // Put the caret back at the end of the new input. This also makes sure the input scrolls
                // to reveal the new text.
                input.selectionStart = range.end + value.length;
                input.selectionEnd = input.selectionStart;

                this.resetAutocomplete();
                this.didComplete = true;
            },
            resetAutocomplete: function() {
                this.completions = [];
                this.termRange = {};
                this.active = false;
            },
        });
    </script>
</polymer-element>
